Save State Hacking with Visual Basic v2.1 by:

The_Fake_God (The_Fake_God@hotmail.com)
http:/www.retrobase.com/fakegod
April, 2001

Table Contents
----------------------------------------
/ 0. Introduction                      /
/ 1. Stuff youll need                 /
/ 2. Visual Basic Variables            /
/ 3. Hex or Decimal                    /
/ 4. Saved State Hacking               /
/ 5. Visual Basic Complete project     /
/ 6. Tips and Tricks                   /
/ 7. Special Thanks                    /
----------------------------------------

--<Introduction>--

Save State Hacking is the action of altering specific addresses of a binary file, most likely, a
memory dump. This is quite easy to learn. Ill attempt to teach you how to do Save States Editors
with Visual Basic and even how to find the offsets (briefly). Also if you already know how to 
hack states, you may find some nice tricks on editing weird and non VB variables like three bytes
ones. If you need anything more specific, mail me to see what can be done.


--<Stuff youll need>--

I will use decimal base for the VB project, so you should get a binary editor like Universal Game
Editor (go to my links section). However, if you prefer to hack with HEX, get a hex editor a have 
a base converter with you :) You should get the Eye of the Beholder ROM (only if you want to 
check your results). Also for the source code (included with this file) youll need Visual Basic
6.0 (if you dont have it, use the written code instead)


--<Visual Basic Variables>--


-------------------------------------------------------------------------------------------
Type          Memory       Range
-------------------------------------------------------------------------------------------
Byte          1 Byte       0 to 255

Integer       2 Bytes      -32,768 to 32,767

Long          4 Bytes      -2,147,483,648 to 2,147,483,647

Single        4 Bytes      -3.402823E+38 to -1.401298E-45 for Negative Values
               		    1.401298E-45 to  3.402823E+38 for Positive Values

Double        8 Bytes      -1.79769313486232E+308 to -4.94065645841247E-324 for Neg. Values
	                    4.94065645841247E-324 to  1.79769313486232E+308 for Pos. Values

Currency      8 Bytes      -922,337,203,685,477.5808 to 922,337,203,685,477.5807  

Decimal       12 Bytes     +/-79,228,162,514,264,337,593,543,950,335 if NOT Decimal
                           +/-7.9228162514264337593543950335


What I wanted to show with this table is the range of each variable and how to use them in your
editors. Most Hps variables use an INTEGER. That makes 2-Bytes of data. You may use a long
variable to grab large data like the money or experience. You may have noticed (if you know the
the basic of C) that there are other integers with more range than the 32676 one. These are
called unsigned integers (0 - 65535) Later on this doc Ill teach you how to convert signed to
unsigned (Thanks to Che W. for that one). 


--<Save State Hacking>--

This is the fun part. Im not going to explain how UgeTab found the offset list, instead Ill
give you some tricks and examples. Ok - start!

(Ill assume your playing an RPG, The Eye of the Beholder is used later in the VB code)
Suppose youre looking for the HP. Go into a battle an let the HP go down a little, one or two 
hits would be ok. Now save your state in the first slot,  write down the amount of HP that you 
have after the battle. Now Max up your HP (avoid entering towns or whatever takes a map-change) 
and save in slot #2. Open your UGE (Universal Game Editor, I assume that you already know how to 
use it, (if not, try this site: http://www.angelfire.com/nc/ugetab/) Go into the editor and press 
S to split the screen with the two files (slot #1 & #2) Perform a search for the HP in file #1 
(the one after the battle) and when it matches compare with the other file to see if thats what 
you have got. This is my brief explanation about hackin' states. Take a look at UgeTabs guide 
to learn more tricks about this.  
 

--<Visual Basic>--

Create a new Visual Basic project and add/change the following things.
Im going to explain the elemental part of the source code, there is a lot of copy/paste in there.


Object       Name      
------------------------
Form         frmEditor       
TextBox      txtHP   
TextBox      txtSTR
TextBox      txtINT
TextBox      txtWIZ
TextBox      txtDEX
TextBox      txtCON
TextBox      txtCHA
TextBox      txtFood
TextBox      txtJob1Lev
TextBox      txtJob2Lev
TextBox      txtJob3Lev
TextBox      txtJobExp1
TextBox      txtJobExp2
TextBox      txtJobExp3


The code goes like this, see comments for more details:

' This code should be inside a module
Public Sub OpenState(Filename)

With frmEditor
If Filename = "" Then Exit Sub
Screen.MousePointer = vbHourglass
FF = FreeFile
 
Open Filename For Binary As #FF

' Local variables declare

' For reading one byte data
Dim CurVal as Byte

' For reading four byte data
Dim CurLng as Long

'******************
' Character 1 Part
'******************
' Always use signs to know what you're hacking, it helps a lot later, specially when
' debbuging.

' STR
' Most binary editors open files starting from 0, Vb starts from 1, so Add 1 to the
' address you have
Get #FF, 4396 + 1, CurVal
.txtSTR = CurVal

' INT
Get #FF, 4400 + 1, CurVal
.txtINT = CurVal

' WIS
Get #FF, 4402 + 1, CurVal
.txtWIZ = CurVal

' DEX
Get #FF, 4404 + 1, CurVal
.txtDEX = CurVal

' CON
Get #FF, 4406 + 1, CurVal
.txtCON = CurVal

' CHA
Get #FF, 4408 + 1, CurVal
.txtCHA = CurVal

' HP
Get #FF, 4410 + 1, CurVal
.txtHP = CurVal

' FOOD
Get #FF, 4418 + 1, CurVal
.txtFood = CurVal

' JOB 1 LEVEL
Get #FF, 4419 + 1, CurVal
.txtJob1Lev = CurVal

' JOB 2 LEVEL
Get #FF, 4420 + 1, CurVal
.txtJob2Lev = CurVal

' JOB 3 LEVEL
Get #FF, 4421 + 1, CurVal
.txtJob3Lev = CurVal

' JOB 1 EXP
' Notice that I'm using CurLong to grab larger data
Get #FF, 4422 + 1, CurLong
.txtJobExp1 = CurLong

' JOB 2 EXP
Get #FF, 4426 + 1, CurLong
.txtJobExp2 = CurLong

' JOB 3 EXP
Get #FF, 4430 + 1, CurLong
.txtJobExp3 = CurLong

Close #FF
Screen.MousePointer = vbDefault
End With
End Sub

' Now to save them is quite the same

Public Sub SaveState(Filename)
With frmEditor
If Filename = "" Then Exit Sub
Screen.MousePointer = vbHourglass
FF = FreeFile
Open Filename For Binary As #FF
'******************

' I always use the val method to avoid errors (for instance, letters instead of numbers)
' ALWAYS! use C-Type (Cbyte, CLng, CInt) when saving directly from a textbox or whatever 
' that isn't a dimensioned variable

' Character 1 stuff 
Put #FF, 4396 + 1, CByte(Val(.txtSTR))
Put #FF, 4400 + 1, CByte(Val(.txtINT))
Put #FF, 4402 + 1, CByte(Val(.txtWIZ))
Put #FF, 4404 + 1, CByte(Val(.txtDEX))
Put #FF, 4406 + 1, CByte(Val(.txtCON))
Put #FF, 4408 + 1, CByte(Val(.txtCHA))
Put #FF, 4410 + 1, CByte(Val(.txtHP))
Put #FF, 4418 + 1, CByte(Val(.txtFood))
Put #FF, 4419 + 1, CByte(Val(.txtJob1Lev))
Put #FF, 4420 + 1, CByte(Val(.txtJob2Lev))
Put #FF, 4421 + 1, CByte(Val(.txtJob3Lev))
Put #FF, 4422 + 1, CLng(Val(.txtJobExp1))
Put #FF, 4426 + 1, CLng(Val(.txtJobExp2))
Put #FF, 4430 + 1, CLng(Val(.txtJobExp3))

Close #FF

' To update screen
Call OpenState(Filename)

Screen.MousePointer = vbDefault
End With
End Sub


--<Tips & Tricks>--

Common problems that you may face when making SSE (Save State Editors) are different data types. 
Like unsigned integers or three byte variables (very common in RPGs).
Here are some data conversions to help:

From signed to unsigned integers:

' Copyright: Che Weng http://che.darkmazda.com
' Thanks a lot man!
' Noticed that this function accept a Hexadecimal preformated parameter
' for instance: 04CB <-- NOT--> 4CB


' Function that format the passed parameter
Public Function GetInteger(value)
    Dim A$
    A$ = Hex(value)
    If Len(A$) = 1 Then A$ = "000" & A$
    If Len(A$) = 2 Then A$ = "00" & A$
    If Len(A$) = 3 Then A$ = "0" & A$
    GetInteger = ConvertHex(A$)
End Function

Function ConvertHex(h$) As Currency
    Dim Tmp$
    Dim lo1 As Integer, lo2 As Integer
    Dim hi1 As Long, hi2 As Long
    Const Hx = "&H"
    Const BigShift = 65536
    Const LilShift = 256, Two = 2
    Tmp = h
    'In case "&H" is present
    If UCase(Left$(h, 2)) = "&H" Then Tmp = Mid$(h, 3)
    'In case there are too few characters
    Tmp = Right$("0000000" & Tmp, 8)
    'In case it wasn't a valid number
    If IsNumeric(Hx & Tmp) Then
        lo1 = CInt(Hx & Right$(Tmp, Two))
        hi1 = CLng(Hx & Mid$(Tmp, 5, Two))
        lo2 = CInt(Hx & Mid$(Tmp, 3, Two))
        hi2 = CLng(Hx & Left$(Tmp, Two))
        ConvertHex = CCur(hi2 * LilShift + lo2) * BigShift + (hi1 * LilShift) + lo1
    End If
End Function

' Above functions can be used like this
  Get #1, 12345 + 1, MyInteger
  Text1.Text = GetInteger(MyInteger)

These are for reading three byte variables, it accepts two parameters the Integer parameter and 
a byte parameter. Example:

' Be sure to format the integer with the Signed/Unsigned Method
' Functions created by: The_Fake_God

' Example This is how you call it
' Suppose you're reading a 3 byte variable
  Get #FF, 130511 + 1, CurInt
  Get #FF, 130511 + 3, CurVal
  .txtCExp = tByte(GetInteger(CurInt), CurVal)

' The functions 

Function cHex(val)
 Select Case Len(val)
  Case 1, 3, 5, 7: val = "0" & val
 End Select
 cHex = val
End Function

Function tByte(int1, byt1) As Long
 lo = cHex(Hex(int1))
 hi = cHex(Hex(byt1))
 Lo1 = Left(lo, 2)
 Lo2 = Right(lo, 2)
 If hi = "00" Then
  tByte = CLng("&H" & lo)
 Else
  tByte = CLng("&H" & hi & Lo1 & Lo2)
 End If
End Function

Try new methods, experiment with other bases to reach your objective. Hex stuff is always useful
in this data conversion.

--<Special Thanks>--

I want to thank UgeTab for helping me boosting my site and programs. Also, thanks to Che Weng, I
learned most of this stuff from him. Thanks to Maxim and thats it. Drop me a line at:

The_Fake_God@hotmail.com
http://www.retrobase.com/fakegod

Be sure to look there for more tutorials, editors and source code.
Take Care.


